import { Reducer } from "redux";
import { get, set, mergeWith, cloneDeep } from "lodash";
import { ADD_COMPONENT, SELECT_ELEM, SET_CURRENT_ELEMENT_PROPS, DELETE_COMPONENT, RESET_COMPONENT, SET_COMPONENT_NAME, SET_BLUEPRINT } from "../constants";
import { IAction } from "../type";

export interface IComponent {
  name: string;  // 组件名称
  key: string;   // 组件key值
  node: string;  // 组件类型
  id: string;    // 组件唯一标识
  index: number; // 组件的顺序，通过此调节组件的层级
  props: { [key: string]: any };  // 组件的静态属性
  style: { [key: string]: any };  // 样式配置
  dataSource: { [key: string]: any };  // 编辑态数据源配置
  // TODO: 组件的动作属性
}
export interface IEditorState {
  components: IComponent[];  // 页面上所有组件的集合
  currentElement: string;    // 当前正在编辑的组件id
  pageProps: any;            // 整个页面的属性设置
  blueprint: any;            // 页面蓝图配置
}
const defaultEditorData: IEditorState = {
  components: [],
  currentElement: "",
  pageProps: {},
  blueprint: undefined
}

const editorReducer: Reducer<IEditorState, IAction> = (state = defaultEditorData, action) => {
  const components = state.components;
  const pageProps = state.pageProps;
  switch (action.type) {
    case ADD_COMPONENT:
      components.push(action.payload);
      return {
        ...state,
        components: [...components]
      }
    case SELECT_ELEM:
      return {
        ...state,
        currentElement: action.payload
      }
    case SET_CURRENT_ELEMENT_PROPS:
      let { type, value, activeId } = action.payload;
      const currentComp = components.find(comp => comp.id === activeId);
      if (currentComp && get(currentComp, type)) {
        set(currentComp, type, mergeWith(value, get(currentComp, type), (objValue, srcValue) => (objValue ?? srcValue)));
      }
      /* currentComp不存在时标识对整个页面的设置 */
      if (!currentComp) {
        set(pageProps, type, mergeWith(value, get(pageProps, type), (objValue, srcValue) => (objValue ?? srcValue)))
      }
      return {
        ...state,
        components: [...components],
        pageProps: cloneDeep(pageProps)
      }
    case DELETE_COMPONENT:
      const deleteCompId = action.payload ? action.payload : state.currentElement;
      return {
        ...state,
        components: components.filter(comp => comp.id !== deleteCompId),
        currentElement: ""
      }
    case RESET_COMPONENT:
      return {
        ...state,
        components: action.payload
      }
    case SET_COMPONENT_NAME:
      const currentComponent = components.find(item => item.id === action.payload.id);
      currentComponent && set(currentComponent, "name", action.payload.name);
      return { ...state }
    case SET_BLUEPRINT:
      return {
        ...state,
        blueprint: action.payload
      }
    default:
      return state;
  }
}

export default editorReducer;